package com.dfhc.util.aes;


import com.dfhc.util.ConvertHelper;
import com.dfhc.util.StringHelper;

/**
 * MD5 参考 gibberish-aes.js 实现
 * @author 龙色波
 *
 */
public class MD5 {
	 /**
	  * 向左移动
	  * @param a
	  * @param s
	  * @return
	  */
	 private int rotateLeft(int lValue, int iShiftBits) {
		 return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
     }
	 /**
	  * 增加无符号
	  * @param lX
	  * @param lY
	  * @return
	  */
     private int addUnsigned(int lX, int lY) {
    	 int lX4,
         lY4,
         lX8,
         lY8,
         lResult;
    	 
    	 int eight =0x80000000;
    	 int four = 0x40000000;
    	 int three = 0x3FFFFFFF;
    	 int c = 0xC0000000;
    	 
         lX8 = lX & eight;//(lX & 0x80000000);
         lY8 = lY & eight;
         lX4 = lX & four;
         lY4 = lY & four;
         lResult = (lX &three)+ (lY& three);
         if ((lX4 & lY4)>0) {
             return (lResult ^ eight ^ lX8 ^ lY8);
         }
         if ((lX4 | lY4)>0) {
             if ((lResult & four)>0) {
                 return (lResult ^ c ^ lX8 ^ lY8);
             } else {
                 return (lResult ^ four ^ lX8 ^ lY8);
             }
         } else {
             return (lResult ^ lX8 ^ lY8);
         }
     }
     
     private int f(int x, int y, int z) {
    	   return (x & y) | ((~x) & z);
     }
     
     private int g(int x, int y, int z) {
    	   return (x & z) | (y & (~z));
     }
     private int h(int x, int y, int z) {
    	 return (x ^ y ^ z);
     }
     private int funcI(int x, int y, int z) {
    	   return (y ^ (x | (~z)));
     }

     private int ff(int a, int b,int c, int d, int x, int s,int ac) {
    	 
         a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac));
         return addUnsigned(rotateLeft(a, s), b);
     }

     private int gg(int a, int b,int  c,int  d,int  x,int  s,int  ac) {
         a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac));
         return addUnsigned(rotateLeft(a, s), b);
     }

     private int hh(int a,int b,int c,int d,int x,int s,int ac) {
         a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac));
         return addUnsigned(rotateLeft(a, s), b);
     }

     private int ii(int a,int b,int c,int d,int x,int s,int ac) {
         a = addUnsigned(a, addUnsigned(addUnsigned(funcI(b, c, d), x), ac));
         return addUnsigned(rotateLeft(a, s), b);
     }

     /**
      * 转换为16进制
      * @param lValue
      * @return
      */
     private int[] wordToHex(int lValue) {
    	 int lInt;
         int lCount;
         int wordToHexArr [] = new int[4];
         for (lCount = 0; lCount <= 3; lCount++) {
             lInt =  (lValue >>> (lCount * 8)) & 255;
             wordToHexArr[lCount] = lInt;
          }
         return wordToHexArr;
         //return ConvertHelper.toHex(lValue);
     }
     /**
      * 字符串转十六进制
      * @param str
      * @param size
      * @return
      */
     private int[] strhex (String str,int size) {
         int i;
         int ret[] = null;
         ret = new int[str.length()/size];
         for (i=0; i<str.length(); i+=size){        
        	 if(i+size<str.length()){
        		 ret[i/size] = ConvertHelper.toHex(str.substring(i,i+size));
        	 }else{
        		 ret[i/size] = ConvertHelper.toHex(str.substring(i));
        	 }
         }
         return ret;
     }
     /**
      * md5编码
      * @param numArr
      * @return
      */
     public int[] encode(int numArr[]){
    	 int x[] = null;
         int k;
         int AA;
         int BB;
         int CC;
         int DD;
         int a;
         int b;
         int c;
         int d;
         int[] rnd =null;
         
         rnd = strhex("67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391",8);

         x = convertToWordArray(numArr);

         a = rnd[0];
         b = rnd[1];
         c = rnd[2];
         d = rnd[3];

         for (k = 0; k < x.length; k += 16) {
             AA = a;
             BB = b;
             CC = c;
             DD = d;
             a = ff(a, b, c, d, x[k + 0], 7, rnd[4]);
             d = ff(d, a, b, c, x[k + 1], 12, rnd[5]);
             c = ff(c, d, a, b, x[k + 2], 17, rnd[6]);
             b = ff(b, c, d, a, x[k + 3], 22, rnd[7]);
             a = ff(a, b, c, d, x[k + 4], 7, rnd[8]);
             d = ff(d, a, b, c, x[k + 5], 12, rnd[9]);
             c = ff(c, d, a, b, x[k + 6], 17, rnd[10]);
             b = ff(b, c, d, a, x[k + 7], 22, rnd[11]);
             a = ff(a, b, c, d, x[k + 8], 7, rnd[12]);
             d = ff(d, a, b, c, x[k + 9], 12, rnd[13]);
             c = ff(c, d, a, b, x[k + 10], 17, rnd[14]);
             b = ff(b, c, d, a, x[k + 11], 22, rnd[15]);
             a = ff(a, b, c, d, x[k + 12], 7, rnd[16]);
             d = ff(d, a, b, c, x[k + 13], 12, rnd[17]);
             c = ff(c, d, a, b, x[k + 14], 17, rnd[18]);
             b = ff(b, c, d, a, x[k + 15], 22, rnd[19]);
             a = gg(a, b, c, d, x[k + 1], 5, rnd[20]);
             d = gg(d, a, b, c, x[k + 6], 9, rnd[21]);
             c = gg(c, d, a, b, x[k + 11], 14, rnd[22]);
             b = gg(b, c, d, a, x[k + 0], 20, rnd[23]);
             a = gg(a, b, c, d, x[k + 5], 5, rnd[24]);
             d = gg(d, a, b, c, x[k + 10], 9, rnd[25]);
             c = gg(c, d, a, b, x[k + 15], 14, rnd[26]);
             b = gg(b, c, d, a, x[k + 4], 20, rnd[27]);
             a = gg(a, b, c, d, x[k + 9], 5, rnd[28]);
             d = gg(d, a, b, c, x[k + 14], 9, rnd[29]);
             c = gg(c, d, a, b, x[k + 3], 14, rnd[30]);
             b = gg(b, c, d, a, x[k + 8], 20, rnd[31]);
             a = gg(a, b, c, d, x[k + 13], 5, rnd[32]);
             d = gg(d, a, b, c, x[k + 2], 9, rnd[33]);
             c = gg(c, d, a, b, x[k + 7], 14, rnd[34]);
             b = gg(b, c, d, a, x[k + 12], 20, rnd[35]);
             a = hh(a, b, c, d, x[k + 5], 4, rnd[36]);
             d = hh(d, a, b, c, x[k + 8], 11, rnd[37]);
             c = hh(c, d, a, b, x[k + 11], 16, rnd[38]);
             b = hh(b, c, d, a, x[k + 14], 23, rnd[39]);
             a = hh(a, b, c, d, x[k + 1], 4, rnd[40]);
             d = hh(d, a, b, c, x[k + 4], 11, rnd[41]);
             c = hh(c, d, a, b, x[k + 7], 16, rnd[42]);
             b = hh(b, c, d, a, x[k + 10], 23, rnd[43]);
             a = hh(a, b, c, d, x[k + 13], 4, rnd[44]);
             d = hh(d, a, b, c, x[k + 0], 11, rnd[45]);
             c = hh(c, d, a, b, x[k + 3], 16, rnd[46]);
             b = hh(b, c, d, a, x[k + 6], 23, rnd[47]);
             a = hh(a, b, c, d, x[k + 9], 4, rnd[48]);
             d = hh(d, a, b, c, x[k + 12], 11, rnd[49]);
             c = hh(c, d, a, b, x[k + 15], 16, rnd[50]);
             b = hh(b, c, d, a, x[k + 2], 23, rnd[51]);
             a = ii(a, b, c, d, x[k + 0], 6, rnd[52]);
             d = ii(d, a, b, c, x[k + 7], 10, rnd[53]);
             c = ii(c, d, a, b, x[k + 14], 15, rnd[54]);
             b = ii(b, c, d, a, x[k + 5], 21, rnd[55]);
             a = ii(a, b, c, d, x[k + 12], 6, rnd[56]);
             d = ii(d, a, b, c, x[k + 3], 10, rnd[57]);
             c = ii(c, d, a, b, x[k + 10], 15, rnd[58]);
             b = ii(b, c, d, a, x[k + 1], 21, rnd[59]);
             a = ii(a, b, c, d, x[k + 8], 6, rnd[60]);
             d = ii(d, a, b, c, x[k + 15], 10, rnd[61]);
             c = ii(c, d, a, b, x[k + 6], 15, rnd[62]);
             b = ii(b, c, d, a, x[k + 13], 21, rnd[63]);
             a = ii(a, b, c, d, x[k + 4], 6, rnd[64]);
             d = ii(d, a, b, c, x[k + 11], 10, rnd[65]);
             c = ii(c, d, a, b, x[k + 2], 15, rnd[66]);
             b = ii(b, c, d, a, x[k + 9], 21, rnd[67]);
             a = addUnsigned(a, AA);
             b = addUnsigned(b, BB);
             c = addUnsigned(c, CC);
             d = addUnsigned(d, DD);
         }

         return ConvertHelper.addInts(ConvertHelper.addInts(ConvertHelper.addInts(wordToHex(a),wordToHex(b)),wordToHex(c)),wordToHex(d));
     }
     private int[] convertToWordArray(int[] numArr) {
    	 int lWordCount;
         int lMessageLength = numArr.length;
         int lNumberOfWords_temp1 = lMessageLength + 8;
         int lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
         int lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
         int lWordArray[] = new int[lNumberOfWords];
         int lBytePosition = 0,
         lByteCount = 0;
         
         
         while (lByteCount < lMessageLength) {
             lWordCount = (lByteCount - (lByteCount % 4)) / 4;
             lBytePosition = (lByteCount % 4) * 8;
             //byte 
             lWordArray[lWordCount] =  (lWordArray[lWordCount] | (ConvertHelper.toInt(numArr[lByteCount]) << lBytePosition));             
             lByteCount++;
         }
         lWordCount = (lByteCount - (lByteCount % 4)) / 4;
         lBytePosition = (lByteCount % 4) * 8;
         lWordArray[lWordCount] =  (lWordArray[lWordCount] | (0x80 << lBytePosition));
         lWordArray[lNumberOfWords - 2] =  (lMessageLength << 3);
         lWordArray[lNumberOfWords - 1] =  (lMessageLength >>> 29);
         return lWordArray;
	}
	/**
      * md5编码
      * @param numArr
      * @return
      */
     public int[] encode(String numArr){
    	 	int convertNumArr[] = new int[numArr.length()];
    	 	
    	 	for(int i=0;i<numArr.length();i++){
    	 		if(StringHelper.isNumber(numArr.charAt(i))){
    	 			convertNumArr[i] = ConvertHelper.toInt(numArr.charAt(i));
    	 		}else{
    	 			convertNumArr[i] = 0;
    	 		}
    	 	}
    	 	return encode(convertNumArr);
     }
}
